﻿using System;
using System.Collections.Generic;
using System.Text;
using ttlang.node;

namespace ttlang.builder.cs
{
    static class FileExporter
    {
        public static void ExportNameSpaceMember(Result result, string name, semantic.TTNameSpace _namespace)
        {
            StringBuilder coder = new StringBuilder();
            coder.AppendLine("using System;");
            //c# 不允许namespace有member，全部用class套起来
            coder.AppendLine("static class " + name);
            coder.AppendLine("{");
            if (_namespace.methods != null)
            {
                foreach (var m in _namespace.methods.Values)
                {
                    BuildMethod(coder, 1, m);
                }
            }
            if (_namespace.vars != null)
            {
                foreach (var v in _namespace.vars.Values)
                {
                    BuildVar(coder, 1, v);
                }
            }
            coder.AppendLine("}");


            var filename = name + ".cs";
            var len = coder.Length;

            result.WriteFile(filename, coder.ToString());
            result.outputFiles[filename] = len;
        }

        public static void ExportType(Result result, string name, semantic.TTType _type)
        {
            StringBuilder coder = new StringBuilder();
            coder.AppendLine("using System;");
            string full = "";
            full = _type.parentContainer?.fullname;
            int deep = 0;
            string space = "";
            if (!string.IsNullOrEmpty(full))
            {
                coder.AppendLine("namespace full");
                coder.AppendLine("{");
                deep = 1;
                space = "    ";
            }

            {
                if (_type.definetype == semantic.DEFINETYPE.CLASS)
                {
                    coder.Append(space);
                    coder.Append("class ");
                    coder.Append(_type.name);
                }
                else if (_type.definetype == semantic.DEFINETYPE.STRUCT)
                {
                    coder.Append(space);
                    coder.Append("struct ");
                    coder.Append(_type.name);
                }
                else
                {
                    throw new Exception("not support yet.");
                }

                coder.Append(space); coder.AppendLine("{");
                if (_type.vars != null)
                {
                    foreach (var v in _type.vars)
                    {
                        BuildTypeVar(coder, deep + 1, v.Value);
                    }
                }
                if (_type.methods != null)
                {
                    foreach (var m in _type.methods)
                    {
                        BuildTypeMethod(coder, deep+1, m.Value);
                    }
                }
                coder.Append(space); coder.AppendLine("}");
            }



            if (!string.IsNullOrEmpty(full))
            {
                coder.AppendLine("namespace full");
                coder.AppendLine("}");
            }

            //write file
            var fullname = _type.fullname.Replace('.', '_');
            var filename = fullname + ".cs";
            var len = coder.Length;
            result.WriteFile(filename, coder.ToString());
            result.outputFiles[filename] = len;

        }
        public static void BuildMethod(StringBuilder coder, int deep, semantic.TTMethod method)
        {

            bool isMain = false;
            if (method.attributes != null)//入口点检查
            {
                for (var i = 0; i < method.attributes.Length; i++)
                {
                    var _m = method.attributes[i].function as Node_Expr_Method;
                    if (_m.method.name == "EntryPoint")
                    {
                        isMain = true;
                    }
                }
            }
            string space = "";
            for (var i = 0; i < deep; i++)
                space += "    ";
            coder.Append(space);

            //將來加上各種modifer以後，逻辑应该是有entrypoint的必须是static函数，现在还没区分static
            //所有namespace里面的也是static函数
            if (isMain)
                coder.Append("static ");

            coder.Append(cs.TypeConverter.ConvertType(method.tttype.fullname));
            coder.Append(" " + (isMain ? "Main" : method.name) + "(");
            for (var i = 0; i < method.args.Length; i++)
            {
                coder.Append(cs.TypeConverter.ConvertType(method.args[i].argtype.fullname) + " " + method.args[i].name);
                if (i != method.args.Length - 1)
                    coder.Append(",");
            }
            coder.AppendLine(")");


            if (method.body != null)
            {
                cs.NodeExporter.BuildNode_Code(coder, method.body, deep);
            }
            else
            {
                coder.AppendLine(space + "{");
                coder.AppendLine(space + "}");
            }
        }
        public static void BuildVar(StringBuilder coder, int deep, semantic.TTVar method)
        {

        }
        public static void BuildTypeMethod(StringBuilder coder, int deep, semantic.TTMethod method)
        {
            string space = "";
            for (var i = 0; i < deep; i++)
                space += "    ";
            bool ctor = method.name == "constructor";

            coder.Append(space);
            coder.Append("public ");
            if (!ctor)
            {
                coder.Append(" ");
                coder.Append(cs.TypeConverter.ConvertType(method.tttype.fullname));

                coder.Append(method.name);
            }
            else
            {
                coder.Append(method.container.name);
            }
            
          
            coder.Append("(");
            for (var i = 0; i < method.args.Length; i++)
            {
                coder.Append(cs.TypeConverter.ConvertType(method.args[i].argtype.fullname) + " " + method.args[i].name);
                if (i != method.args.Length - 1)
                    coder.Append(",");
            }
            coder.Append(")");
            if(method.body!=null)
            {
                cs.NodeExporter.BuildNode_Code(coder, method.body, deep);
            }
            else
            {
                coder.AppendLine(";");
            }
        }
        public static void BuildTypeVar(StringBuilder coder, int deep, semantic.TTVar _var)
        {
            string space = "";
            for (var i = 0; i < deep; i++)
                space += "    ";
            coder.Append(space);
            coder.Append("public ");
            coder.Append(TypeConverter.ConvertType(_var.tttype.fullname));
            coder.Append(" ");
            coder.Append(_var.name);
            if(_var.initvalue!=null)
            {
                coder.Append(" = ");
                NodeExporter.BuildNode_Expr(coder, _var.initvalue);
            }
            coder.AppendLine(";");
        }
    }
}
